#ifndef _NET_ADDR_H_
#define _NET_ADDR_H_

#include "net_define.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#include <string>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#endif

namespace as
{

namespace inet
{

class AS_DLL NetAddr
{
public:
    NetAddr()
    {

    }
    
    NetAddr(std::string_view h, int p, bool isIpv6 = false)
    {
        set_addr(h, p, isIpv6);
    }

    NetAddr(std::string_view ip, bool isIpv6 = false)
    {
        //todo 127.0.0.1:9001
    }

    void set_addr(std::string_view h, int p, bool isIpv6 = false)
    {
        m_ip = h;
        m_port = p;
        if(strchr(h.data(), ':'))
        {
            to_ipv6(h, p);
        }
        else
        {
            to_ipv4(h, p);
        }
    }

    NetAddr& to_ipv4(std::string_view h, int p)
    {
        if(inet_pton(AF_INET, h.data(), &this->ipv4.sin_addr) == 1)
        {
            ipv4.sin_family = AF_INET;
            ipv4.sin_port = htons(p);
            m_len = sizeof(ipv4);
        }
        return *this;
    }

    NetAddr& to_ipv6(std::string_view h, int p)
    {
        return *this;
    }

    const sockaddr_in& getIpv4()
    {
        return ipv4;
    }

    const sockaddr_in6& getIpv6()
    {
        return ipv6;
    }

    const sockaddr* getIpv()
    {
        uint8_t af = get_af();
        if(af == AF_INET)
            return (const sockaddr*)&ipv4;
        else if(af == AF_INET6)
            return (const sockaddr*)&ipv6;
        return nullptr;
    }

    uint8_t get_af() const
    {
        if(m_len == sizeof(ipv4))
            return AF_INET;
        else if(m_len == sizeof(ipv6))
            return AF_INET6;
        return -1;
    }

    uint8_t get_len() const
    {
        return m_len;
    }

    const std::string_view GetAddr()const { return addr; }

private:
    union
    {
        struct sockaddr_in ipv4;
        struct sockaddr_in6 ipv6;
    };

    char addr[32] = {0};
    std::string_view m_ip;
    int m_port = 0;
    uint8_t m_len = 0;
};

}
}
#endif